package com.sen.rbac.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sen.common.common.bo.SysResourceBO;
import com.sen.common.common.bo.SysRoleGroupBO;
import com.sen.common.common.response.MessageResult;
import com.sen.common.common.response.PageVo;
import com.sen.common.common.response.ResultMsgEnum;
import com.sen.common.common.util.SnowflakeIdWorker;
import com.sen.common.tenant.config.TenantContextHolder;
import com.sen.common.user.config.UserContextHolder;
import com.sen.rbac.constant.RbacConstant;
import com.sen.rbac.dto.SysRoleDto;
import com.sen.rbac.exception.RbacException;
import com.sen.rbac.mapper.SysResourceDao;
import com.sen.rbac.mapper.SysRoleAccountDao;
import com.sen.rbac.mapper.SysRoleDao;
import com.sen.rbac.mapper.SysRoleResourceDao;
import com.sen.rbac.model.SysResource;
import com.sen.rbac.model.SysRole;
import com.sen.rbac.model.SysRoleAccount;
import com.sen.rbac.model.SysRoleResource;
import com.sen.rbac.service.ResourceService;
import com.sen.rbac.service.RoleService;
import com.sen.rbac.vo.SysResourceVO;
import com.sen.rbac.vo.SysRoleGroupVO;
import com.sen.rbac.vo.SysRoleVO;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

import static com.sen.rbac.enums.RbacMsgEnum.*;


/**
 * @author esjiang
 */
@Service
@Slf4j
public class RoleServiceImpl implements RoleService {

    @Resource
    SysRoleDao sysRoleDao ;

    @Resource
    SysRoleAccountDao sysRoleAccountDao ;

    @Resource
    SysRoleResourceDao sysRoleResourceDao ;

    @Resource
    ModelMapper modelMapper ;

    @Resource
    SysResourceDao sysResourceDao ;

    @Resource
    ResourceService resourceService ;

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public MessageResult crud(SysRoleDto sysRoleDto) {
        MessageResult messageResult = MessageResult.bizFailed(role_crud_failed);
        String operationType = sysRoleDto.getOperationType();
        if (StrUtil.equals(operationType, RbacConstant.ADD)){
            if (add(sysRoleDto)) {
                messageResult = MessageResult.success();
            }
        }
        if (StrUtil.equals(operationType, RbacConstant.UPD)){
            if (update(sysRoleDto)){
                messageResult = MessageResult.success();
            }
        }
        if (StrUtil.equals(operationType, RbacConstant.DEL)){
            if (delete(sysRoleDto.getCode())){
                messageResult = MessageResult.success() ;
            }
        }
        if (StrUtil.equals(operationType, RbacConstant.LIST)){
            PageVo<SysRoleVO> list = list(sysRoleDto);
            messageResult = MessageResult.success(list) ;
        }
        return messageResult;
    }

    boolean add(SysRoleDto sysRoleDto){
        SysRole sysRole = modelMapper.map(sysRoleDto, SysRole.class);
        sysRole.setCode(SnowflakeIdWorker.generateId().toString());
        sysRole.setEntityCode(UserContextHolder.getPeople().getEntityCode());
        sysRole.setGroupCode(UserContextHolder.getPeople().getEntityType());
        sysRole.setTenantCode(TenantContextHolder.getTenant());
        return sysRoleDao.insert(sysRole) == 1;
    }

    boolean update(SysRoleDto sysRoleDto){
        SysRole sysRole1 = getSysRole(sysRoleDto.getCode());
        SysRole sysRole = modelMapper.map(sysRoleDto, SysRole.class);
        return sysRoleDao.update(sysRole, Wrappers.<SysRole>lambdaQuery().eq(SysRole::getCode,sysRole1.getCode())) == 1 ;
    }

    boolean delete(String code){
        /** 校验角色是否存在 */
        getSysRole(code);
        /** 当存在账户关联了该角色时，不能删除 */
        Integer integer = sysRoleAccountDao.selectCount(Wrappers.<SysRoleAccount>lambdaQuery().eq(SysRoleAccount::getRoleCode, code));
        if (integer > 0){
            throw new RbacException(role_exist_account);
        }
        return sysRoleDao.delete(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getCode, code)) == 1 ;
    }

    PageVo<SysRoleVO> list(SysRoleDto sysRoleDto){
        LambdaQueryWrapper<SysRole> sysRoleLambdaQueryWrapper = Wrappers.<SysRole>lambdaQuery();
        if (StrUtil.isNotBlank(sysRoleDto.getName())){
            sysRoleLambdaQueryWrapper.like(SysRole::getName,sysRoleDto.getName());
        }
        if (!UserContextHolder.isSuperAdmin()){
            /** 增加主体编码查询 */
            sysRoleLambdaQueryWrapper.eq(SysRole::getEntityCode,UserContextHolder.getPeople().getEntityCode()) ;
            /** 区划条件查询 */
            sysRoleLambdaQueryWrapper.eq(SysRole::getTenantCode, TenantContextHolder.getTenant()) ;
        }
        Page<SysRole> sysRolePage = sysRoleDao.selectPage(new Page<>(sysRoleDto.getPage(), sysRoleDto.getPageSize()), sysRoleLambdaQueryWrapper);
        PageVo<SysRoleVO> sysRoleVOPageVo = new PageVo<>();
        if (CollectionUtil.isNotEmpty(sysRolePage.getRecords())){
            sysRoleVOPageVo.setTotal(sysRolePage.getTotal());
            List<SysRoleVO> collect = sysRolePage.getRecords().stream().map(sysRole -> modelMapper.map(sysRole, SysRoleVO.class)).collect(Collectors.toList());
            sysRoleVOPageVo.setList(collect);
        }
        return sysRoleVOPageVo ;
    }

    @Override
    public List<SysRoleGroupVO> findRoleGroup() {
        List<SysRoleGroupBO> roleGroup = sysRoleDao.findRoleGroup();
        if (CollectionUtil.isNotEmpty(roleGroup)){
            return roleGroup.stream().map(group -> modelMapper.map(group, SysRoleGroupVO.class)).collect(Collectors.toList());
        }
        return CollectionUtil.newArrayList();
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean relatedResource(String roleCode, List<String> resourceCodes) {
        List<SysRole> sysRoles = sysRoleDao.selectList(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getCode, roleCode));
        if (CollUtil.isEmpty(sysRoles)){
            throw new RbacException(ResultMsgEnum.RECORD_NOT_EXIST) ;
        }
        /** 先删除关联的资源信息 */
        sysRoleResourceDao.delete(Wrappers.<SysRoleResource>lambdaQuery().eq(SysRoleResource::getRoleCode,roleCode));
        /** 各个插入 */
        int i = 0 ;
        for (String resourceCode : resourceCodes) {
            SysRoleResource sysAuthority = new SysRoleResource();
            sysAuthority.setResourceCode(resourceCode);
            sysAuthority.setRoleCode(roleCode);
            i = i + sysRoleResourceDao.insert(sysAuthority);
        }
        return i == resourceCodes.size() ;
    }

    private SysRole getSysRole(String code){
        List<SysRole> sysRoles = sysRoleDao.selectList(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getCode,code));
        if (CollectionUtil.isEmpty(sysRoles)){
            throw new RbacException(role_not_exist);
        }
        if (sysRoles.size() != 1){
            throw new RbacException(role_data_exception);
        }
        return sysRoles.get(0) ;
    }

    /***
     * 查询账户所拥有的资源
     * @param userName 账户名
     * @return
     */
    @Override
    public List<SysResourceBO> getResourcesByUserNameForGateway(String userName) {
        List<SysResource> resourceByUserName = resourceService.getResourcesByUserNameForGateway(userName);
        return resourceByUserName.stream().map(sysMenu -> modelMapper.map(sysMenu, SysResourceBO.class)).collect(Collectors.toList());
    }

    /**
     * 根据角色查询资源
     * @param code
     * @return
     */
    @Override
    public List<SysResourceVO> findResourceByRoleCode(String code){
        List<SysResource> menuByRoleCode = sysResourceDao.findResourceByRoleCode(CollectionUtil.newArrayList(code));
        if (CollectionUtil.isEmpty(menuByRoleCode)){
            return CollectionUtil.newArrayList() ;
        }
        return menuByRoleCode.stream().map(sysResource -> modelMapper.map(sysResource, SysResourceVO.class)).collect(Collectors.toList());
    }


}
